#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <error.h>
#include <errno.h>



#define INTERFACE_DESCRIPTION_BLOCK     0x00000001
#define PACKET_BLOCK                    0x00000002
#define SIMPLE_PACKET_BLOCK             0x00000003
#define NAME_RESOLUTION_BLOCK           0x00000004
#define INTERFACE_STATISTICS_BLOCK      0x00000005
#define ENHANCED_PACKET_BLOCK           0x00000006
#define SECTION_HEADER_BLOCK            0x0A0D0D0A

#define MIN(A, B) ((A) < (B) ? (A) : (B))

int main(int argc, char *argv[])
{
    char *input_filename;
    FILE *input_filep;
    struct block_header_str {
        uint32_t type;
        uint32_t length;
    } block_header;
    uint32_t body_align_len;
    char block_body[BUFSIZ];
    size_t bytes_read;


    if (argc != 2)
        error_at_line(EXIT_FAILURE, 0, __FILE__, __LINE__,
                "FATAL ERROR: Wrong number of arguments.\n"
                "Usage: %s <input_filename>", argv[0]);

    input_filename = argv[1];

    if ((input_filep = fopen(argv[1], "r")) == NULL)
        error_at_line(EXIT_FAILURE, errno, __FILE__, __LINE__,
                "FATAL ERROR: %s", input_filename);

    while (!feof(input_filep)) {

        if ((bytes_read = (fread(&block_header, 1, sizeof(block_header),
                    input_filep))) != sizeof(block_header)) {
            if ((bytes_read == 0) && (feof(input_filep)))
                continue;
            else if (ferror(input_filep))
                error_at_line(EXIT_FAILURE, 0, __FILE__, __LINE__,
                        "FATAL ERROR: Error on reading: %s.",
                        input_filename);
            else
                error_at_line(EXIT_FAILURE, 0, __FILE__, __LINE__,
                        "INVALID FILE FORMAT: Block header not found.");
        }

        switch (block_header.type) {
            case INTERFACE_DESCRIPTION_BLOCK:
                printf("INTERFACE DESCRIPTION BLOCK\n");
                break;
            case PACKET_BLOCK:
                printf("PACKET BLOCK\n");
                break;
            case SIMPLE_PACKET_BLOCK:
                printf("SIMPLE PACKET BLOCK\n");
                break;
            case NAME_RESOLUTION_BLOCK:
                printf("NAME RESOLUTION BLOCK\n");
                break;
            case INTERFACE_STATISTICS_BLOCK:
                printf("INTERFACE STATISTICS BLOCK\n");
                break;
            case ENHANCED_PACKET_BLOCK:
                printf("ENHANCED PACKET BLOCK\n");
                break;
            case SECTION_HEADER_BLOCK:
                printf("SECTION HEADER BLOCK\n");
                break;
            default:
                error_at_line(EXIT_FAILURE, 0, __FILE__, __LINE__,
                        "INVALID FILE FORMAT: Unknown block header type.");
                break;
        }

        body_align_len = block_header.length
            + ((block_header.length % 4) ? (4 - (block_header.length % 4)) 
                    : 0)
            - sizeof(block_header);

        while (body_align_len > 0) {

            if ((bytes_read = fread(block_body, 1,
                            MIN(body_align_len, sizeof(block_body)),
                            input_filep)) !=
                    MIN(body_align_len, sizeof(block_body))) {
                if (feof(input_filep))
                    error_at_line(EXIT_FAILURE, 0, __FILE__, __LINE__,
                            "INVALID FILE FORMAT: Unexpected end of file.");
                else if (ferror(input_filep))
                    error_at_line(EXIT_FAILURE, 0, __FILE__, __LINE__,
                            "FATAL ERROR: Error on reading: %s.", 
                            input_filename);
                else
                    error_at_line(EXIT_FAILURE, 0, __FILE__, __LINE__,
                            "FATAL ERROR: Unknow read error: %s.",
                            input_filename);
            }

            body_align_len -= bytes_read;
        }

    }

    exit(EXIT_SUCCESS);
}
